package com.yh.csx.bsf.ods;

import com.alibaba.druid.pool.DruidDataSource;
import com.yh.csx.bsf.core.db.DbConn;
import com.yh.csx.bsf.core.util.PropertyUtils;
import lombok.var;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import org.springframework.util.StringUtils;

/**
 * 策略解析类
 */
public class StragtegyProvider {
	/**
	 * 获取需要同步的数据库
	 * 
	 * @return
	 */
	public static volatile Map<String, Map<String, String>> DB_MAPS = new HashMap<String, Map<String, String>>();

	public static volatile Map<String, DataSource> DB_SOURCES = new ConcurrentHashMap<String, DataSource>();

	public List<String> getDbs() {
		var array = PropertyUtils.getPropertyCache("canal.dbs", "").split(",");
		return Arrays.asList(array);
	}

	/**
	 * 根据数据库策略解析生成链接
	 * 
	 * @param db
	 * @return
	 */
	public DbConn getDb(String db) {
		Map<String, String> info = getDbInfo(db);
		if (info == null)
			return null;
		// 加载数据源连接池
		if (!DB_SOURCES.containsKey(db)) {
			DataSource ds=createDataSource(db,info);
			DB_SOURCES.put(db, ds);
		}
		return new DbConn(DB_SOURCES.get(db));
	}
	
	/**
	 * 根据数据库策略解析生成链接
	 * 
	 * @param db
	 * @return
	 */
	public DbConn getDbByIP(String ip) {
		Map<String, String> info = getDbInfo(ip);
		if (info == null)
			return null;
		// 加载数据源连接池
		if (!DB_SOURCES.containsKey(ip)) {
			DataSource ds=createDataSource(ip,info);
			DB_SOURCES.put(ip, ds);
		}
		return new DbConn(DB_SOURCES.get(ip));
	}
	
	/**
	 * 获取数据源
	 * */
	public DataSource getDS(String db) {
		Map<String, String> info = getDbInfo(db);
		if (info == null)
			return null;
		// 加载数据源连接池
		if (!DB_SOURCES.containsKey(db)) {
			DataSource ds=createDataSource(db,info);
			DB_SOURCES.put(db, ds);
		}
		return DB_SOURCES.get(db);
	}
	/**
	 * 创建数据源
	 * */
	private DataSource createDataSource(String db, Map<String, String> dbInfo) {
		DruidDataSource ds = new DruidDataSource();
		ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
		ds.setUrl("jdbc:mysql://" + dbInfo.get("address") + "/" + db + "?zeroDateTimeBehavior=convertToNull");
		ds.setUsername(dbInfo.get("username"));
		ds.setPassword(dbInfo.get("password"));
		ds.setInitialSize(1);
		ds.setMinIdle(1);
		ds.setMaxActive(20);
		ds.setMaxWait(120000);
		ds.setTestWhileIdle(true);
		ds.setValidationQuery("select 1;");
		ds.setValidationQueryTimeout(5000);
		ds.setTimeBetweenEvictionRunsMillis(60000);
		ds.setMinEvictableIdleTimeMillis(300000);
		try {
			ds.init();
		} catch (SQLException e) {
			ds.close();
			throw new RuntimeException(e);

		}
		return ds;
	}

	public Map<String, String> getDbInfo(String db) {
		String address = "spring.datasource.{0}.address";
		String username = "spring.datasource.{0}.username";
		String password = "spring.datasource.{0}.password";
		var c = "";
		if (!PropertyUtils.getPropertyCache(address.replace("{0}", db), "").isEmpty()) {
			c = db;
		} else if (!PropertyUtils.getPropertyCache(address.replace("{0}", removeNumber(db)), "").isEmpty()) {
			c = removeNumber(db);
		}
		if (c.isEmpty())
			return null;
		var map = StragtegyProvider.DB_MAPS.get(c);
		if (map != null) {
			return map;
		} else {
			map = new HashMap<String, String>();
			map.put("address", PropertyUtils.getPropertyCache(address.replace("{0}", c), ""));
			map.put("username", PropertyUtils.getPropertyCache(username.replace("{0}", c), ""));
			map.put("password", PropertyUtils.getPropertyCache(password.replace("{0}", c), ""));
			StragtegyProvider.DB_MAPS.put(c, map);
			return map;
		}

	}
	/**
	 * 传入db和table，根据策略解析离线仓库对应的合并表
	 * 
	 * @param db
	 * @param table
	 * @return
	 */
	public String getBlackTable(String db, String table) {
		String stragtegy = "black.list";
		String value = PropertyUtils.getPropertyCache(stragtegy, "");
		if(StringUtils.hasText(value)) {
			String[] tables=value.split(",");
			for(String temp:tables) {
				if(temp.equalsIgnoreCase(db+"."+table)){
					return db+"."+table;
				}
			}
		}
		return null;
		
	}
	/**
	 * 传入db和table，根据策略解析离线仓库对应的合并表
	 * 
	 * @param db
	 * @param table
	 * @return
	 */
	public String getTable(String db, String table) {
		String stragtegy = "strategy.{0}.{1}";
		String value = PropertyUtils.getPropertyCache(stragtegy.replace("{0}", db).replace("{1}", table), "");
		if (StringUtils.hasText(value)) {
			return value;					
		}else {
			String target = PropertyUtils.getPropertyCache(stragtegy.replace("{0}", removeNumber(db)).replace("{1}", removeNumber(table)), "");
			if (StringUtils.hasText(target)) {
				return target;
			}			
			return db + "." + table;
		}
	}

	public String getTargetTable(String db, String table) {
		return getTable(db,table);
	}
	/**
	 * 传入db和table，根据策略解析离线仓库对应的合并表
	 * 
	 * @param db
	 * @param table
	 * @return
	 */
	public String getDataBase(String db) {
		return removeNumber(db);
	}

	public int getCanalBatchSize() {
		return PropertyUtils.getPropertyCache("canal.batch.size", 1024);
	}

	private  static String removeNumber(String str) {
		String removeNumStr= str.replaceAll("[^A-Z_a-z]", "");
		while(removeNumStr.endsWith("_")) {
			removeNumStr=removeNumStr.substring(0,removeNumStr.length()-2);
		}
		return removeNumStr;
	}
}
